/* $Id:special.cc $ */
/*
   Copyright (C) 2007 by Jurjen Stellingwerff <jurjen@stwerff.xs4all.nl>
   Part of the Moros Project http://moros.sourceforge.net/

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License version 3.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY.

   See the COPYING file for more details.
*/

#define DEBUG_ROUTINE "special"

#include <sstream>
#include <fstream>
#include "../general/util.h"
#include "../general/log.h"
#include "../general/channel.h"
#include "special.h"
#include "skill.h"
#include "special.h"
#include "../general/general.h"

special::special() {
    skill=0;
    name="";
    description="";
    type=-1;
    prerequisite=0;
    group="";
}

// Field : skill

class skill& special::getSkill() const { if (skill==0) throw nullpointer(); return *skill; }
void special::setSkill(class skill &v) { skill=&v; }

// Field : name

const string special::getName() const { return name; }
void special::setName(const string v) { name=v; }

// Field : description

const string special::getDescription() const { return description; }
void special::setDescription(const string v) { description=v; }

// Field : type

const string specialType[]={"common","uncommon"};
const int special::getType() const { return type; }
const string special::showType() const {
    if (type<0) return "";
    else return specialType[type];
}
void special::setType(const int  v) {
    if (v<0 || (unsigned int)v >= sizeof specialType/sizeof specialType[0]) type=-1;
    else type=v;
}
void special::setType(const string v) {
    type=-1;
    loopArray(specialType, tp, string) {
        if (v==*tp) {type=tp_i; break; }
    }
    if (type==-1) dbg_state("Enumerate special.type %s has unknown '%s'", getName().c_str(), v.c_str());
}

// Field : prerequisite

class special& special::getPrerequisite() const { if (prerequisite==0) throw nullpointer(); return *prerequisite; }
void special::setPrerequisite(class special &v) { prerequisite=&v; }

// Field : group

const string special::getGroup() const { return group; }
void special::setGroup(const string v) { group=v; }

void special::save(class channel &ch) {
    ch.write("special", "");
    ch.write("s", getSkill().getName());
    ch.write("n", getName());
    ch.write("d", getDescription());
    ch.write("t", getType());
    ch.write("p", getPrerequisite().getName());
    ch.write("g", getGroup());
}

void special::load(class channel &ch) {
    if (ch.key=="s" || ch.key=="skill") {
        if (!skill_repo.isSkill(ch.value)) {
            dbg_state("link unknown skill %s", ch.value.c_str());
            class skill rec;
            rec.setName(ch.value);
            skill_repo.setSkill(rec);
        }
        setSkill(skill_repo.getSkill(ch.value));
        ch.next();
    }
    if (ch.key=="n" || ch.key=="name") { setName(ch.value); ch.next(); }
    if (ch.key=="d" || ch.key=="description") { setDescription(ch.value); ch.next(); }
    if (ch.key=="t" || ch.key=="type") { setType(ch.value); ch.next(); }
    if (ch.key=="p" || ch.key=="prerequisite") {
        if (!special_repo.isSpecial(ch.value)) {
            dbg_state("link unknown special %s", ch.value.c_str());
            class special rec;
            rec.setName(ch.value);
            special_repo.setSpecial(rec);
        }
        setPrerequisite(special_repo.getSpecial(ch.value));
        ch.next();
    }
    if (ch.key=="g" || ch.key=="group") { setGroup(ch.value); ch.next(); }
}

void special::xml(ofstream &f, int l, int r) {
    f << ncpy(l, "  ") << "<special name=\"" << xml_encode(getName()) <<
    "\" description=\"" << xml_encode(getDescription()) <<
    "\" type=\"" << showType() <<
    "\" group=\"" << xml_encode(getGroup()) <<
    "\">" << endl;
    if (r<2) try {
        getSkill().xml(f,l+1,r+1);
        getPrerequisite().xml(f,l+1,r+1);
    } catch (nullpointer n) {}
    f << ncpy(l, "  ") << "</special>" << endl;
}

// Repository

specialRepository special_repo;

class special& specialRepository::getSpecial(const string v) { return specials[v]; }
void specialRepository::setSpecial(class special& v) {
    if (v.getName()=="") throw unnamed();
    specials[v.getName()]=v;
}
map<string,class special>& specialRepository::listSpecial() { return specials; }
void specialRepository::delSpecial(const string v) { specials.erase(v); }
const bool specialRepository::isSpecial(const string v) const { return specials.count(v)>0; }
void specialRepository::save(class channel &ch) {
    loopSpecials(rec) {
        rec->save(ch);
    }
}

bool specialRepository::load(class channel &ch) {
    if (ch.key=="special") {
        ch.next();
        class special rec;
        rec.load(ch);
        setSpecial(rec);
        return true;
    }
    return false;
}
